
const net = require('net')
// 使用parser 处理body
const parser = require('./parser.js')

// 实现一个请求类
class Request {
  constructor(options) { // 构造函数
    this.method = options.method || 'GET'
    this.host = options.host
    this.port = options.port || 80
    this.path = options.path || '/'
    this.headers = options.headers || {}
    this.body = options.body || {}
    // 把 options 里的数据判断一下
    if (!this.headers['Content-Type']) {
      this.headers['Content-Type'] = 'application/x-www-form-urlencecoded'
    }
    // 如果是 json 就转字符串
    if (this.headers['Content-Type'] === 'application/json')
      this.bodyText = JSON.stringify(this.body)
    // 如果是 form 表单数据 就把 键值对 拼接起来
    else if (this.headers['Content-Type'] === 'application/x-www-form-urlencecoded')
      this.bodyText = Object.keys(this.body).map(key => `${key}=${encodeURIComponent(this.body[key])}`).join('&')
    // 设置请求头 的 Content-Length 属性 如果传的不对，就是一个非法的请求
    this.headers['Content-Length'] = this.bodyText.length
  }

  send(connection) { // 把请求发送到服务器里
    return new Promise((resolve, reject) => {
      const parser = new ResponseParser()
      // 判断connection 是否传入 没有就根据host、port新建一个
      if (connection) {
        connection.write(this.toString())
      } else {
        connection = net.createConnection({
          host: this.host,
          port: this.port
        }, () => {
          connection.write(this.toString())
        })
      }
      connection.on('data', data => {
        console.log(data.toString())
        parser.receive(data.toString())
        if (parser.isFinished) { // 如果已经是完成的状态
          resolve(parser.response) // 返回 值
          connection.end() // 结束连接
        }
      })

      connection.on('error', err => { // 返回报错
        reject(err)
        connection.end() // 结束连接
      })

      resolve('123')
    })
  }

  toString() { // 拼接字符串
    return `${this.method} ${this.path} HTTP/1.1\r\n${Object.keys(this.headers).map(key => `${key}: ${this.headers[key]}`).join('\r\n')}\r\r${this.bodyText}`
  }

}

class ResponseParser { // 解析数据
  consturctor() {
    this.WAITING_STATUS_LINE = 0
    this.WAITING_STATUS_LINE_END = 1
    this.WAITING_HEADER_NAME = 2
    this.WAITING_HEADER_SPACE = 3
    this.WAITING_HEADER_VALUE = 4
    this.WAITING_HEADER_LINE_END = 5
    this.WAITING_HEADER_BLOCK_END = 6
    this.WAITING_BODY = 7

    this.current = this.WAITING_STATUS_LINE
    this.statusLine = ''
    this.headers = {}
    this.headerName = ''
    this.headerValue = ''
    this.bodyParser = null
  }

  get isFinished() {
    return this.bodyParser && this.bodyParser.isFinished
  }
  get response() {
    this.statusLine.match(/HTTP\/1.1 ([0-9+]) ([\s\S]+)/)
    return {
      statusCode: RegExp.$1,
      statusText: RegExp.$2,
      headers: this.headers,
      body: this.bodyParser.content.join('')
    }
  }


  receive(string) { // 把字符串拆分成单个进行解析
    for(let i = 0; i< string.length; i++) {
      this.receiveChar(string.charAt(i))
    }
  }

  receiveChar(char) { // 状态机分析文本结构 判断 返回对应值
    if (this.current === this.WAITING_STATUS_LINE) {
      if (char === '\r') {
        this.current = this.WAITING_STATUS_LINE_END
      } else {
        this.statusLine += char
      }

    } else if (this.current === this.WAITING_STATUS_LINE_END) {
      if (char === '\n') {
        this.current = this.WAITING_HEADER_NAME
      }

    } else if (this.current === this.WAITING_HEADER_NAME) {
      if (char === ':') {
        this.current = this.WAITING_HEADER_SPACE
      } else if (char === '\r') {
        this.current = this.WAITING_HEADER_BLOCK_END
        if (this.headers['Transfer-Encoding'] === 'chunked')
          this.bodyParser = new TrunkedBodyParser() // 编写
      } else {
        this.headerName += char
      }

    } else if (this.current === this.WAITING_HEADER_SPACE) {
      if (char === ' ') {
        this.current = this.WAITING_HEADER_VALUE
      }
    } else if (this.current === this.WAITING_HEADER_VALUE) {
      if (char === '\r') {
        this.current = this.WAITING_HEADER_LINE_END
        this.headers[this.headerName] = this.headerValue
        this.headerName = ''
        this.headerValue = ''
      } else {
        this.headerValue += char
      }

    } else if (this.current === this.WAITING_HEADER_LINE_END) {
      if (char === '\n') {
        this.current = this.WAITING_HEADER_NAME
      }

    } else if (this.current === this.WAITING_HEADER_BLOCK_END) {
      if (char === '\n') {
        this.current = this.WAITING_BODY
      }

    } else if (this.current === this.WAITING_BODY) { // 结束
      console.log(char)
      this.bodyParser.receiveChar(char) // 把最终结果让 bodyParser 处理
    }
  }

}

class TrunkedBodyParser {
  constructor() {
    this.WAITING_LENGTH = 0
    this.WAITING_LENGTH_LINE_END = 1
    this.READING_TRUNK = 2
    this.WAITING_NEW_LINE = 3
    this.WAITING_NEW_LINE_END = 4
    this.length = 0
    this.content = []
    this.isFinished = false
    this.current = this.WAITING_LENGTH
  }

  receiveChar(char) {
    if (this.current === this.WAITING_LENGTH) {
      if (char === '\r') {
        if (this.length === 0) {
          this.isFinished = true
        }
        this.current = this.WAITING_LENGTH_LINE_END
      } else { // 转 16 进制
        this.length *= 16
        this.length += parseInt(char, 16)
      }
    } else if (this.current === this.WAITING_LENGTH_LINE_END) {
      if (char === '\n') {
        this.current = this.READING_TRUNK
      }
    } else if (this.current === this.READING_TRUNK) {
      if (this.isFinished) {
        return
      }
      this.current.push(char)
      this.length --
      if (this.length === 0) {
        this.current = this.WAITING_NEW_LINE
      }
    } else if (this.current === this.WAITING_NEW_LINE) {
      if (char === '\r') {
        this.current = this.WAITING_NEW_LINE_END
      }
    } else if (this.current === this.WAITING_NEW_LINE_END) {
      if (char === '\n') {
        this.current = this.WAITING_LENGTH
      }
    }
  }
}


// 子调用函数
void async function() {
  let request = new Request({
    method: 'POST', // 请求方式 get 、 put 等
    host: '127.0.0.1', // 本地服务器
    port: '8088', // 端口号
    path: '/', 
    headers: { // 请求头
      ["X-Foo2"]: 'customed'
    },
    body: { // 请求体
      name: 'charlie_lee'
    }
  })
  // 调用send方法，得到 返回值
  let response = await request.send()

  console.log(response)
  // 实际上是要异步分段处理，这里处理一次性全部返回的body
  let dom = parser.parseHTML(response.body)
  console.log(dom)
}();









